package com.itcoon.cloud.framework.webmvc.exception;

import com.itcoon.cloud.framework.ex.exception.BaseException;
import com.itcoon.cloud.framework.ex.exception.PseudoException;
import com.itcoon.cloud.framework.webmvc.exception.handler.GlobalExceptionHandler;
import com.itcoon.cloud.framework.webmvc.exception.listener.event.GlobalExceptionEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * <p> </p>
 *
 * @author 俞淼霞
 * @since 2019-09-04
 */
@ControllerAdvice(annotations = {Controller.class, ControllerAdvice.class})
public class GlobalExceptionController implements Ordered {

    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionController.class);

    private final List<GlobalExceptionHandler> exceptionHandlers;
    private final ApplicationEventPublisher publisher;

    public GlobalExceptionController(List<GlobalExceptionHandler> exceptionHandlers, ApplicationEventPublisher publisher) {
        this.exceptionHandlers = exceptionHandlers;
        this.publisher = publisher;
    }

    @ExceptionHandler(Exception.class)
    public void handleException(HttpServletResponse response, Exception ex) {
        doHandleException(response, ex);
    }

    @ResponseBody
    @ExceptionHandler(PseudoException.class)
    public void handleException(HttpServletResponse response, PseudoException ex) {
      doHandleException(response, ex);
    }

    @ExceptionHandler(BaseException.class)
    public void handleException(HttpServletResponse response, BaseException ex) {
       doHandleException(response, ex);
    }

    @ExceptionHandler({BindException.class})
    public void handleBindException(HttpServletResponse response, BindException ex) {
       doHandleException(response, ex);
    }

    @ExceptionHandler({MethodArgumentNotValidException.class})
    public void handleMessageArgumentNotValidException(HttpServletResponse response, MethodArgumentNotValidException ex) {
        doHandleException(response, ex);
    }


    private void doHandleException(HttpServletResponse response, Exception e){
        publisher.publishEvent(new GlobalExceptionEvent<>(e));
        for (GlobalExceptionHandler exceptionHandler : exceptionHandlers) {
            if(exceptionHandler.support(e)){
                exceptionHandler.handle(response, e);
                break;
            }
        }
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 10;
    }
}
